package com.rock.app.controller;

import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.eova.aop.AopContext;
import com.eova.aop.MetaObjectIntercept;
import com.eova.common.Easy;
import com.eova.common.utils.xx;
import com.eova.common.utils.db.DbUtil;
import com.eova.config.PageConst;
import com.eova.model.EovaLog;
import com.eova.model.MetaField;
import com.eova.model.MetaObject;
import com.eova.service.sm;
import com.eova.template.common.config.TemplateConfig;
import com.eova.template.common.util.TemplateUtil;
import com.eova.widget.WidgetManager;
import com.eova.widget.WidgetUtil;
import com.jfinal.core.Controller;
import com.jfinal.core.NotAction;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.rock.app.base.MetaApiUtil;
import com.rock.app.base.OpenControllerBase;
import com.rock.sys.service.RockMetaServUtil;

import cn.hutool.core.util.StrUtil;


public class AppFormController extends OpenControllerBase {
	
	final Controller ctrl = this;

	/** 元对象业务拦截器 **/
	protected MetaObjectIntercept intercept = null;

	/** 异常信息 **/
	private String errorInfo = "";

	
    public void index() {

    }

    /**
     * 查询列表
     * @param username
     * @param password
     * @throws Exception 
     */
    public void queryList() throws Exception {

        String metaCode = getPara("metaCode");
        String metaItemStr = getPara("metaItem");
        
        if (StrUtil.isBlank(metaCode)) {
            renderFailJson(107, "can not get metaCode");
            return;
        }

        Map transMappre = JSON.parseObject(metaItemStr);
        Map<String, String> transMap = transMappre;
        
        //透传所有请求参数
		Map<String,String> queryMap = this.getParas();

		int pageNumber = getParaToInt(PageConst.PAGENUM, 1);
		int pageSize = getParaToInt(PageConst.PAGESIZE, 10000);

		MetaObject object = sm.meta.getMeta(metaCode);
//		Menu menu = Menu.dao.findByCode(menuCode);

		intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());

		// 构建查询
		List<Object> parmList = new ArrayList<Object>();
		String sql = WidgetManager.buildQuerySQL(ctrl, null, object, intercept, parmList, true);

		// 转换SQL参数
		Object[] paras = new Object[parmList.size()];
		parmList.toArray(paras);
		Page<Record> page = Db.use(object.getDs()).paginate(pageNumber, pageSize, "select *", DbUtil.formatSql(sql), paras);

		// 查询后置任务
		if (intercept != null) {
			AopContext ac = new AopContext(ctrl, page.getList(),object);
			intercept.queryAfter(ac);
		}

		// 备份Value列，然后将值列转换成Key列
		WidgetUtil.copyValueColumn(page.getList(), object.getPk(), object.getFields());
		// 根据表达式将数据中的值翻译成汉字
		WidgetManager.convertValueByExp(this,object, object.getFields(), page.getList());

        List<Record> metaResList = page.getList();

        List<Record> resList = new ArrayList<Record>();
        
        //如果metaItemStr为空，则不需要进行转换，前端根据需要获取字段值
        if(!StrUtil.isBlank(metaItemStr)) {
        	for(Record metaMap : metaResList) {
        		Record resMap = transformation(metaMap,transMap);
        		resList.add(resMap);
        	}
        } else {
        	resList = metaResList;
        }
        
//        List<Map<String,Object>> resList  = metaResList.stream().map(x->transformation(x,transMap)).collect(Collectors.toList());
        System.out.println("最新json：");
        System.out.println(JSON.toJSONString(resList));

        Map<String,Object> data = new HashMap<String, Object>();
        data.put("metaCode", metaCode);
        data.put("dataList", resList);
        
        renderOkDataJson(data);
    }

    /**
     * 去新增
     * @param username
     * @param password
     */
    public void goAdd() {

        String metaCode = getPara(0);
        
        if (StrUtil.isBlank(metaCode)) {
            renderFailJson(107, "can not get metaCode");
            return;
        }

		List<MetaField> metaResList = MetaApiUtil.getFieldAddList(metaCode,this);
        
        renderOkDataJson(metaResList);
    }

    /**
     * 去更新
     * @param username
     * @param password
     * @throws Exception 
     */
    public void goUpdate() throws Exception {

        String metaCode = getPara(0);
        String id = getPara(1);
        
        if (StrUtil.isBlank(metaCode) || StrUtil.isBlank(id)) {
            renderFailJson(107, "can not get metaCode or id");
            return;
        }

		// 获取关联参数
		Record fixed = WidgetManager.getRef(this);
				
		AopContext ac = new AopContext(ctrl);
		ac.fixed = fixed;
		
		// 初始化数据

		// 获取主键的值
		Object pkValue = getPara(1);
		
		MetaObject object = sm.meta.getMeta(metaCode);
		
		// 根据主键获取对象
		Record record = null;
		if(!xx.isEmpty(pkValue))
		 record = Db.use(object.getDs()).findById(object.getView(), object.getPk(), pkValue);
		
		if(record == null){
//			setAttr("model", true);
//			record = new Record();
			
			errorInfo = "没有该主键值对应的数据记录";
			renderJson(new Easy(errorInfo));
			return;
		}
		
		Map<String,List<MetaField>> um = MetaApiUtil.getFieldUpdateList(metaCode, record, this);
		List<MetaField> fieldUpdateList = um.get("updateFields");
		//隐藏的字段一并返回
//		List<MetaField> updateHiddenFields = um.get("updateHiddenFields");

		ac.object = object;
		ac.record = record;
		
		//查询自定义按钮
		 List<Record> btns = Db.find("select * from t_s_app_metabtn where meta_code=? and app_id=?", metaCode, this.getCurrentApp().getId());
		
		// 业务拦截
		intercept = TemplateUtil.initMetaObjectIntercept(ac.object.getBizIntercept());
		if (intercept != null) {
			intercept.updateInit(ac);
		}

        Map<String,Object> data = new HashMap<String, Object>();
        data.put("fixed", fixed);
//		data.put("record", record);
		data.put("metaCode", metaCode);
		data.put("fieldUpdateList", fieldUpdateList);
		data.put("btnList", btns);
//		data.put("updateHiddenFields", updateHiddenFields);
        
        renderOkDataJson(data);
    }
    
	/**
	 * 转换列表json为前端需要的数据
	 * @param metaMap
	 * @param transMap
	 * @return
	 */
    @NotAction
	public Record transformation(Record metaMap,Map<String, String> transMap){
		Record newData = new Record();
		
		for(Map.Entry<String, String> a: transMap.entrySet()){
			newData.set(a.getKey(), metaMap.get(a.getValue()));
		}
		newData.set("id", metaMap.get("id"));
		return newData;
	}
	
    
    /**
     * 增加数据记录
     * @param username
     * @param password
     * @throws Exception 
     */
    public void doAdd() throws Exception {

    	String metaCode = getPara(0);
        String postData = getRawData();
        if (StrUtil.isBlank(metaCode) || StrUtil.isBlank(postData)) {
            renderFailJson(107, "can not get metaCode or form data");
            return;
        }

		final MetaObject object = sm.meta.getMeta(metaCode);
		
		System.out.println("元数据接收数据测试" + ctrl.getParaValues("name"));

		Record r = new Record();
        //预置归属APP
		r.set("app_id", this.getCurrentApp().getId());

		// 获取当前操作数据
		MetaApiUtil.buildData(this, object, r, object.getPk(), true);

		intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
		// 事务(默认为TRANSACTION_READ_COMMITTED)
		boolean flag = Db.use(object.getDs()).tx(new IAtom() {
			@Override
			public boolean run() throws SQLException {
				try {
					AopContext ac = new AopContext(ctrl, r,object);

					//必填字段检查
					Map res = MetaApiUtil.checkFieldRequiredAdd(metaCode,r);
					if(!(boolean)res.get("isPass")) {
						errorInfo = res.get("reqCn") + "不能为空";
						return false;
					}
					
					// 新增前置任务
					if (intercept != null) {
						String msg = intercept.addBefore(ac);
						if (!xx.isEmpty(msg)) {
							errorInfo = msg;
							return false;
						}
					}

					if (!xx.isEmpty(object.getTable())) {
						// add table
						// 剥离虚拟字段
						Record t = WidgetManager.peelVirtual(r);
						Db.use(object.getDs()).save(object.getTable(), object.getPk(), r);
						// 还原虚拟字段
						r.setColumns(t);
					} else {
						// update view
						 WidgetManager.operateView(TemplateConfig.ADD, object, r);
						// 视图无法自动操作，请自定义元对象业务拦截完成持久化逻辑！
					}

					// 新增后置任务
					if (intercept != null) {
						String msg = intercept.addAfter(ac);
						if (!xx.isEmpty(msg)) {
							errorInfo = msg;
							return false;
						}
					}
				} catch (Exception e) {
					errorInfo = "新增异常:" + TemplateUtil.buildException(e);
					return false;
				}
				return true;
			}
		});

		// AOP提示信息
		if (!flag) {
			renderFailJson(errorInfo);
			return;
		}

		// 记录新增日志
		EovaLog.dao.info(this, EovaLog.ADD, object.getStr("code"),null);
		
		errorInfo = null;
		// 新增成功之后
		if (intercept != null) {
			try {
				ArrayList<Record> records = new ArrayList<Record>();
				records.add(r);

				AopContext ac = new AopContext(this, records,object);
				String msg = intercept.addSucceed(ac);
				if (!xx.isEmpty(msg)) {
					errorInfo = msg;
				}
			} catch (Exception e) {
				errorInfo = TemplateUtil.buildException(e);
				renderFailJson("新增成功,addSucceed拦截执行异常!" + errorInfo);
				return;
			}
		}
        
        renderOkDataJson(errorInfo);
    }
    

    /**
     * 更新数据记录
     * @param username
     * @param password
     * @throws Exception 
     */
    public void doUpdate() throws Exception {

    	String metaCode = getPara(0);
        String postData = getRawData();
        if (StrUtil.isBlank(metaCode) || StrUtil.isBlank(postData)) {
            renderFailJson(107, "can not get metaCode or form data");
            return;
        }


		final MetaObject object = sm.meta.getMeta(metaCode);

		Record r = new Record();
		// 获取当前操作数据
		MetaApiUtil.buildData(this, object, r, object.getPk(), false);
		
		final Object pkValue = r.get(object.getPk());

		intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());
		// 事务(默认为TRANSACTION_READ_COMMITTED)
		boolean flag = Db.use(object.getDs()).tx(new IAtom() {
			@Override
			public boolean run() throws SQLException {
				try {
					AopContext ac = new AopContext(ctrl, r,object);

					//必填字段检查
					Map res = MetaApiUtil.checkFieldRequiredUpdate(metaCode,r);
					if(!(boolean)res.get("isPass")) {
						errorInfo = res.get("reqCn") + "不能为空";
						return false;
					}
					
					// 修改前置任务
					if (intercept != null) {
						String msg = intercept.updateBefore(ac);
						if (!xx.isEmpty(msg)) {
							errorInfo = msg;
							return false;
						}
					}

					
					if (!xx.isEmpty(object.getTable())) {
						// update table
						// 剥离虚拟字段
						Record t = WidgetManager.peelVirtual(r);
						Db.use(object.getDs()).update(object.getTable(), object.getPk(), r);
						// 还原虚拟字段
						r.setColumns(t);
					} else {
						// update view
						 WidgetManager.operateView(TemplateConfig.UPDATE, object, r);
						// 视图无法自动操作，请自定义元对象业务拦截完成持久化逻辑！
					}

					// 修改后置任务
					if (intercept != null) {
						String msg = intercept.updateAfter(ac);
						if (!xx.isEmpty(msg)) {
							errorInfo = msg;
						}
					}
				} catch (Exception e) {
					errorInfo = "修改异常:" + TemplateUtil.buildException(e);
					return false;
				}
				return true;
			}

		});

		// AOP提示信息
		if (!flag) {
			renderFailJson(errorInfo);
			return;
		}

		// 记录新增日志
		EovaLog.dao.info(this, EovaLog.UPDATE, object.getStr("code") + "[" + pkValue + "]",null);
		
		intercept = null;
		// 修改成功之后
		if (intercept != null) {
			try {
				ArrayList<Record> records = new ArrayList<Record>();
				records.add(r);

				AopContext ac = new AopContext(this, records,object);
				String msg = intercept.updateSucceed(ac);
				if (!xx.isEmpty(msg)) {
					errorInfo = msg;
				}
			} catch (Exception e) {
				errorInfo = TemplateUtil.buildException(e);
				renderFailJson("修改成功,updateSucceed拦截执行异常!" + errorInfo);
				return;
			}
		}
        
        renderOkDataJson(errorInfo);
    }
    
	
	/**
	 * 二维码档案二维码，扫码编辑
	 * @throws Exception 
	 */
	public void qrScanEdit() throws Exception {
		
		//档案查看地址，必须传入2个参数，分别是1位参数元数据编码，2位是查询条件组合，字段前必须带query_，例如：/t_nb_cattle?query_code=1000376&id=1000
		String metaCode = getPara(0);
		
		if (StrUtil.isBlank(metaCode)) {
			this.renderFailJson("参数错误，无法进入编辑");
        	return;
        }
		
		
		int pageNumber = getParaToInt(PageConst.PAGENUM, 1);
		int pageSize = getParaToInt(PageConst.PAGESIZE, 10000);
		
		System.out.println("进入二维码查询ID" + metaCode + this.getPara());

		MetaObject object = sm.meta.getMeta(metaCode);
//		Menu menu = Menu.dao.findByCode(menuCode);

		intercept = TemplateUtil.initMetaObjectIntercept(object.getBizIntercept());

		// 构建查询
		List<Object> parmList = new ArrayList<Object>();
		//不加查询条件 false
		String sql = WidgetManager.buildQuerySQLNoFilter(false,ctrl, null, object, null, parmList, true);

		// 转换SQL参数
		Object[] paras = new Object[parmList.size()];
		parmList.toArray(paras);
		Page<Record> page = Db.use(object.getDs()).paginate(pageNumber, pageSize, "select *", DbUtil.formatSql(sql), paras);

		// 查询后置任务
		if (intercept != null) {
			AopContext ac = new AopContext(ctrl, page.getList(),object);
			intercept.queryAfter(ac);
		}

		// 备份Value列，然后将值列转换成Key列
		WidgetUtil.copyValueColumn(page.getList(), object.getPk(), object.getFields());
		// 根据表达式将数据中的值翻译成汉字
		WidgetManager.convertValueByExp(this,object, object.getFields(), page.getList());
		
        List<Record> metaResList = page.getList();
        
        if(metaResList.size() == 0) {
			this.renderFailJson("未查询到数据记录，无法启动编辑");
			return;
        } else if(metaResList.size() > 1) {
			this.renderFailJson("查询到多条数据记录，无法启动编辑");
			return;
        }

        //查询唯一记录成功，返回ID
        Map<String,Object> data = new HashMap<String, Object>();
        data.put("metaCode", metaCode);
        data.put("id", metaResList.get(0).get("id"));
        renderOkDataJson(data);
	}
	
    
    /**
     * 文档下载
     * @throws Exception 
     */
    public void docDownload() throws Exception {

        String metaCode = getPara(0);
        String id = getPara(1);

        if (StrUtil.isBlank(metaCode) || StrUtil.isBlank(id)) {
            renderFailJson(107, "can not get metaCode or id");
            return;
        }

		AopContext ac = new AopContext(this);
		MetaObject object = sm.meta.getMeta(metaCode);
		
		File metaDocFile = RockMetaServUtil.getMetaDocFile(object, id, ac);
		this.renderFile(metaDocFile, object.getName() + "-" + id + ".doc");
		
    }

}
